float4x4 World;
float4x4 View;
float4x4 Projection;
float3 LightPosition, Ambient, Diffuse, Specular, CameraPosition;	//world space
float Sheen;	//scalar
int Offset, Tiling;
texture Texture;

sampler DiffuseSampler = sampler_state
{
	Texture = <Texture>;
	AddressU = Wrap;
	AddressV = Wrap;
};
// TODO: add effect parameters here.

struct VertexShaderInput
{
    float4 Position : POSITION0;
	float3 Normal : NORMAL0;
	float2 UV: TEXCOORD0;

    // TODO: add input channels such as texture
    // coordinates and vertex colors here.
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
	float3 Color : COLOR0;

    // TODO: add vertex shader outputs such as colors and texture
    // coordinates here. These values will automatically be interpolated
    // over the triangle, and provided as input to your pixel shader.
};

VertexShaderOutput GouraudVertex(VertexShaderInput input)
{
	VertexShaderOutput output;

	float4 worldPosition = mul(input.Position, World);
	float4 viewPosition = mul(worldPosition, View);
	output.Position = mul(viewPosition, Projection);


	float3 lightDirection = normalize(LightPosition - worldPosition.xyz);
	float3 viewDirection = normalize(CameraPosition - worldPosition.xyz);
	float3 worldNormal = mul(input.Normal, World);
	float3 reflection = -reflect(lightDirection, input.Normal);

	//				Diffuse													Specular
	output.Color = (max(dot(lightDirection, worldNormal), 0) * Diffuse) + (max(pow(dot(reflection, viewDirection), Sheen), 0) * Specular) + Ambient;

	return output;
}

float4 GouraudPixel(VertexShaderOutput input) : COLOR0
{
	// TODO: add your pixel shader code here.

	return float4(input.Color, 1);
}

technique Gouraud
{
	pass Pass1
	{
		// TODO: set renderstates here.

		VertexShader = compile vs_2_0 GouraudVertex();
		PixelShader = compile ps_2_0 GouraudPixel();
	}
}

struct PhongVertexShaderOutput
{
	float4 Position : POSITION0;
	float2 UV : TEXCOORD0;
	float4 WorldPosition : TEXCOORD1;
	float3 WorldNormal : TEXCOORD2;
};

PhongVertexShaderOutput PhongVertex(VertexShaderInput input)
{
	PhongVertexShaderOutput output;

	output.WorldPosition = mul(input.Position, World);
	float4 viewPosition = mul(output.WorldPosition, View);
	output.Position = mul(viewPosition, Projection);
	output.WorldNormal = mul(input.Normal, World);
	output.UV = (input.UV * Tiling) + Offset;

	return output;
}

float4 PhongPixel(PhongVertexShaderOutput input) : COLOR0
{
	float3 lightDirection = normalize(LightPosition - input.WorldPosition.xyz);
	float3 viewDirection = normalize(CameraPosition - input.WorldPosition.xyz);
	float3 reflection = -reflect(lightDirection, input.WorldNormal);
	input.WorldNormal = normalize(input.WorldNormal);
										
	float3 diffuse = max(dot(lightDirection, input.WorldNormal), 0) * tex2D(DiffuseSampler, input.UV) * Diffuse;
	float3 specular = max(pow(dot(reflection, viewDirection), Sheen), 0) * Specular;
	float3 color =  diffuse + specular + Ambient;
	return float4(color, 1);
}

technique Phong
{
	pass Pass1
	{
		// TODO: set renderstates here.

		VertexShader = compile vs_2_0 PhongVertex();
		PixelShader = compile ps_2_0 PhongPixel();
	}
}

/*BlinnVertexShaderOutput BlinnVertex(VertexShaderInput input)
{
    PhongVertexShaderOutput output;

   output.WorldPosition = mul(input.Position, World);
	float4 viewPosition = mul(output.WorldPosition, View);
	output.Position = mul(viewPosition, Projection);
	output.WorldNormal = mul(input.Normal, World);

	return output;	
	//output.Color = max(dot(lightDirection, worldNormal), 0) * float3(0, 1, 0) + max(pow(dot(reflection, viewDirection), Sheen), 0) * float3(0, 0, 1);
}*/

float4 BlinnPixel(PhongVertexShaderOutput input) : COLOR0
{
    float3 lightDirection = normalize(LightPosition - input.WorldPosition.xyz);
	float3 viewDirection = normalize(CameraPosition - input.WorldPosition.xyz);
	//float3 reflection = -reflect(lightDirection, input.WorldNormal);
	input.WorldNormal = normalize(input.WorldNormal);

	//				Diffuse											
	float3 diffuse = max(dot(lightDirection, input.WorldNormal), 0) * tex2D(DiffuseSampler, input.UV) * Diffuse;
	float3 specular = max(pow(dot((lightDirection+viewDirection), viewDirection), Sheen), 0) * Specular;
	float3 color = diffuse + specular + Ambient;
	return float4(color, 1);
}

technique Blinn
{
    pass Pass1
    {
        // TODO: set renderstates here.

        VertexShader = compile vs_2_0 PhongVertex();
        PixelShader = compile ps_2_0 BlinnPixel();
    }
}

/*PhongVertexShaderOutput SchlickVertex(VertexShaderInput input)
{
    PhongVertexShaderOutput output;

	output.WorldPosition = mul(input.Position, World);
	float4 viewPosition = mul(output.WorldPosition, View);
	output.Position = mul(viewPosition, Projection);
	output.WorldNormal = mul(input.Normal, World);

	return output;
}*/

float4 SchlickPixel(PhongVertexShaderOutput input) : COLOR0
{
    float3 lightDirection = normalize(LightPosition - input.WorldPosition.xyz);
	float3 viewDirection = normalize(CameraPosition - input.WorldPosition.xyz);
	float3 reflection = -reflect(lightDirection, input.WorldNormal);
	input.WorldNormal = normalize(input.WorldNormal);
	float t = dot(reflection, viewDirection);

	//				Diffuse											Specular
	float3 diffuse = max(dot(lightDirection, input.WorldNormal), 0) *tex2D(DiffuseSampler, input.UV) * Diffuse; 
	float3 specular = max(t/(Sheen + t - (t * Sheen)), 0) * Specular;
	float3 color = diffuse + specular + Ambient;
	return float4(color, 1);
}

technique Schlick
{
    pass Pass1
    {
        // TODO: set renderstates here.

        VertexShader = compile vs_2_0 PhongVertex();
        PixelShader = compile ps_2_0 SchlickPixel();
    }
}